function diff(oldTree, newTree ) {
    /**
     * 实现思路
     * 当节点类型相同时，看一下属性是否相同，产生一个属性的补丁包{type: 'ATTRS', attrs: {class: 'list-group'}}
     * 新的DOM节点不存在时，补丁包{type: 'REMOVE'， index: xxx}
     * 节点类型不相同时，直接采用替换模式，{type: 'REPLACE'， newNode: newNode}
     * 文本的变化 {type: 'TEXT', text: 1}
     */
    let patches = {};
    let index = 0;
    // 递归树，比较后的结果帮到补丁包中。
    walk(oldTree, newTree, index, patches);

    return patches;
}

const PATCH_TYPE = {
    ATTRS: 'ATTRS',
    TEXT: 'TEXT',
    REMOVE: 'REMOVE',
    REPLACE: 'REPLACE'
}
let Index = 0; // 全局的索引

function isString(node) {
    return Object.prototype.toString.call(node) === '[object String]';
}

function walk(oldNode, newNode, index, patches) {
    let currentPatch = []; // 每个元素当前的补丁对象
    if (!newNode) { // 如果新节点被删除了
        currentPatch.push({
            type: PATCH_TYPE.REMOVE,
            index: index
        })
    } else if (isString(oldNode) && isString(newNode)) {  //如果node是sting类型 // 判断文本是否一致
        if (oldNode !== newNode) {
            currentPatch.push({
                type: PATCH_TYPE.TEXT,
                text: newNode
            })
        }
    } else if (oldNode.type === newNode.type) {
        // 比较属性是否有更改
        let diffAttrs = diffAttr(oldNode.props, newNode.props);
        if (Object.keys(diffAttrs).length) {
            currentPatch.push({
                type: PATCH_TYPE.ATTRS,
                attrs: diffAttrs
            })
        }
        // 比较子节点
        diffChildren(oldNode.children, newNode.children, index, patches)
    } else {
        // 节点被替换了
        currentPatch.push({
            type: PATCH_TYPE.REPLACE,
            newNode
        })
    }

    if (currentPatch.length) { // 当前元素存在补丁，将元素和补丁对应起来放到patches中
        patches[index] = currentPatch;
    }
}

/**
 * 比较新老props
 * @param oldProps
 * @param newProps
 */
function diffAttr(oldProps, newProps) {
    let patch = {};
    // 判断旧的属性和新的属性关系
    for (let key in oldProps) {
        if (oldProps.hasOwnProperty(key)) {
             if (oldProps[key] !== newProps[key]) {
                 patch[key] =  newProps[key] // 新的props如果删除了属性，直接属性值变成undefined就行
             }
        }
    }
    // 判断新的属性与旧的属性的关系，有可能新的属性新增了属性了
    for (let key in newProps) {
        if (newProps.hasOwnProperty(key)) {
            if (!oldProps.hasOwnProperty(key)) { // 如果新的属性不存在于旧的props的自身属性中
                patch[key] = newProps[key]
            }
        }
    }
    return patch;
}

/**
 * 比较新老节点的子节点
 * @param oldNodeChildren
 * @param newNodeChildren
 * @param index
 * @param patches
 */
function diffChildren(oldNodeChildren, newNodeChildren, index, patches) {
    // 比较老的第一个和新的第一个
    oldNodeChildren.forEach((child, idx)  => {
        // 索引不应该是index了
        // index 每次传递给walk时 index是递增的。
        // 所有的index都基于一个全局Index
        walk(child, newNodeChildren[idx], ++Index, patches)
    })
}

export default diff;
export {
    PATCH_TYPE
}